#!/usr/bin/env ruby

require 'socket'
require 'Library'
require 'ftools'
require 'Ftp_Mod'

#doDebug=1
def debug(str)
#	if (doDebug==1) 
		puts "Debug: " << str
#	end
end

module  Database_Manager

public
		
	
#creates the server	
	def Database_Manager.server()
		server = nil
		i = 34567
		while(server == nil)
			begin 
        server = TCPServer.new('127.0.0.1',i)
			rescue Errno::EADDRINUSE
				i = i + 1
				server = nil
			end
		end
		p_file = File.open("port.config",File::CREAT|File::TRUNC|File::RDWR,0777)
		p_file.write(i)
		p_file.close
		configure()
		listen(server) 
		
	end
# everything need to keep the server going 

private


#gets the infomation out of the request string
#request form is 	set <pluginID> <filepath> <artist> <album> <title> <duration> <hash> <playcount> <rating> <last_played>
#request form is 	get <file_name>
#send form is 		<filepath> <artist> <album> <title> <duration> <hash> <playcount> <rating> <last_played>
#request form is 	geth <hash>
#send form is 		<filepath> <artist> <album> <title> <duration> <hash> <playcount> <rating> <last_played>
#request form is 	marco or marco <pluginID>
#send form is 		polo or polo <pluginID> 
#request form is 	new <pluginID> <location> <artist> <album> <title> <duration> <play_count> <rating> <last_played>
#send form is 		conflict  <play_count> <rating> <last_played>
#request form is 	startup <pluginID>
#request form is 	change <location>
#request form is 	ftp get

#send form is 		<time_interval_update> <time_of_last_update> <local_lib_loc> <remote_login_pw> <remote_login_name> <remote_loc>
# this is a line

#request form is ftp set <time_interval_update or ------> 
#<time_of_last_update or -------> <local_lib_loc or -------> <remote_login_pw or ------> <remote_login_name or -------> <remote_loc or -------> 

#send form  <time_interval_update> <time_of_last_update> <local_lib_loc> <remote_login_pw> <remote_login_name> <remote_loc> 

# this is also in a line

# request form is 	ftp to
# request form is 	ftp from
	def Database_Manager.parse_request(request,session)
		debug("Received: #{request}")
		broken = request.scan(/\"[^\"]*\"/)
		i = 0 
		while (i < broken.length)
			broken[i] = broken[i].to_s.scan(/[^\"\n]*/)	
			i = i +1
		end

		debug "Command Base:-#{broken[0]}-"

#used to update the lib
		if broken[0].to_s == "set" then  
			i = 2
			while (i<11)	
				if broken[i].to_s == "------" then	
					broken[i] = nil
				end
			i = i+1
			end
			
			change = Song.new(broken[2].to_s,broken[3].to_s,broken[4].to_s,broken[5].to_s,broken[6].to_s,broken[7].to_s,broken[8].to_s,broken[9].to_s,broken[10].to_s)
			lib_song = @@lib.get_song(change.hash)
			if (lib_song == nil)
				@@lib.add_song(change)
			else
				#@@lib.update_song(change.hash,change.rating,1,change.last_played,change) 	
				@@lib.update_song_data(lib_song)
			end
			@@lib.save(@database_loc)
			doc_change(broken[1],change) 
			session.print("\"OK\"\n")
#this is used on player without libs
		elsif broken[0].to_s == "increment" then
			i = 2
			while (i<11)	
				if broken[i].to_s == "------" then	
					broken[i] = nil
				end
			i = i+1
			end
			change = Song.new(broken[2].to_s,broken[3].to_s,broken[4].to_s,broken[5].to_s,broken[6].to_s,broken[7].to_s,broken[8].to_s,broken[9].to_s,broken[10].to_s)
			lib_song = @@lib.get_song(change.hash)
			if lib_song == nil then
				@@lib.add_song(change)
				lib_song = change
			end
			#@@lib.update_song(lib_song.hash,lib_song.rating,1,lib_song.last_played,lib_song) 
			lib_song.set_playcount(lib_song.playcount+1)
			@@lib.update_song_data(lib_song)
			@@lib.save(@database_loc)
			doc_change(broken[1],lib_song) 
			session.print("\"OK\"\n")
#used to make a connect between plugin and server
		elsif  broken[0].to_s == "marco" then
			if broken.length == 1 then 
				pluginID = get_id()
				config_file = File.new("server.config", File::WRONLY|File::APPEND)
				config_file.write("#{pluginID}\n")
				config_file.close
				configure()
				output = String.new("\"polo\" \"#{pluginID}\"")
        debug output
				session.print "#{output}\n"
		 	else
				session.print "\"polo\"\n"
			end
#given a hash it will send the song to the player
		elsif broken[0].to_s == "geth" then
			l_hash = broken[1].to_s
			
			change = @@lib.get_song(l_hash)
			session.print("#{change.to_response}\n")
#gives the version of the server
		elsif broken[0].to_s == "version" then 
			output = String.new("");
			output << "\"#{@server_version.strip}\""
      debug output
			session.print("#{output}\n")
#for all the new players out there
		elsif broken[0].to_s == "get" then
			l_file = broken[1].to_s
			change = Song.new(l_file,nil,nil,nil,nil,nil,nil,nil,nil)
			if (change !=nil)
				
				lib_song = @@lib.get_song(change.hash)
        			if (lib_song == nil) then
              				@@lib.add_song(change);
	      				debug "Sending #{change.to_response}"
              				session.print("#{change.to_response}\n")
        			else
                			debug "Sending: #{lib_song.to_response}"
                			session.print("#{lib_song.to_response}\n")
        			end
              
			else
        			debug("Error: Song not found")
				session.print("Error: Song not found\n")
			end
		elsif broken[0].to_s == "new" then 
			i = 2
			while (i<11)	
				if broken[i].to_s == "------" then	
					broken[i] = nil
				end
			i = i+1
			end
			change = Song.new(broken[2].to_s,broken[3].to_s,broken[4].to_s,broken[5].to_s,broken[6].to_s,broken[7].to_s,broken[8].to_s,broken[9].to_s,broken[10].to_s)
			lib_song = @@lib.get_song(change.hash)
			if (lib_song ==nil)
				debug("Responding: \"OK\"")
				@@lib.add_song(change)
				session.print("\"OK\"\n")
			elsif (((change.rating.to_i - lib_song.rating.to_i) != 0) and (lib_song.rating.to_i != 0))
					message = String.new("\"conflict\"")
					#plugin must know the song that it is dealing with
					message << " "<< "\"#{lib_song.rating}\"" << " " << "\"#{lib_song.playcount}\"" << " " << "\"#{lib_song.last_played}\"" 
       					debug("Responding #{message}")
					session.print("#{message}\n")
			else 
				@@lib.import_song_data(change)
			        debug("Responding: \"OK\"")
				session.print("\"OK\"\n")
			end
			@@lib.save(@database_loc)
#for all the old players out there
		elsif broken[0].to_s == "startup" then
			f = File.new(broken[1].to_s,"r")
			list = f.readlines
			changes_since_last_load(broken[1],list,session)
			f.close
	   	elsif broken[0].to_s == "ftp" then
			if broken[1].to_s == "set" then
				i = 0
				a = Array.new(broken.length - 2)
				if a.length < 6 then
					
				else
					while(i+2 < broken.length) 
						a[i] = broken[i+2].to_s
						i = i+1	
					end
					@@ftp.ftp_configure(a)
					a = @@ftp.get_all
					i = 0
					m = String.new("")
					while(i < 6)
						m << a[i].chomp("\n") << " "
						i = i +1 
					end
					session.print("#{m}\n")
				end
			elsif broken[1].to_s == "get" then
				s = @@ftp.get_all
				i = 0
				m = String.new("")
				while(i < 6)
					m << s[i].chomp("\n") << " "
					i = i +1 
				end
				session.print("#{m}\n")
			elsif broken[1].to_s == "to" then
				@@ftp.ftp_startup(0)
			elsif broken[1].to_s == "from" then
				@@ftp.ftp_startup(1)
			else 
				print "not a command"
			end
#when the user wants to change the file for the lib					
		else
			print "ERROR: Bad request send to the server\n"
		end
	end
#configures settings
	def Database_Manager.configure()
		config_file = File.new("server.config","r")
		configs = config_file.readlines
		@server_version = configs[0].chomp("\n")
		@database_loc = configs[1].chomp("\n")
		@@lib = Library.new(@database_loc)
		@@ftp = Ftp_File_Manager.new()
		if(configs.length > 2) then
			i = 0
			@current_players = Array(configs.length-2)
			while (i < (configs.length - 2)) 
				 @current_players[i] = configs[i+2]
				i = i + 1
			end
			config_file.close
			i = 0
			while ( i != @current_players.length)
				plug = @current_players[i].to_s.chomp("\n")
				infile = File.new(plug,File::CREAT,0777)
    
				if (infile != nil) then 
					infile.close
				end
				i=i+1
			end
		else
			@current_players = []
		end
	end 
#this function takes care of the changes to the library since the last load
	def Database_Manager.changes_since_last_load(pluginID,state,session)
		i = 0
	      	File.truncate(pluginID.to_s,0)
		message = String.new("")
		while(i < state.size) 
			state[i] = state[i].chomp("\n")
			message << "\"#{state[i]}\"" << " "
			i = i+1
		end
		session.print("#{message}\n")
	end

#listens for sessions forever
	def Database_Manager.listen(server)
		threading = Array.new(2)
		threading[0] = "ftp_th"
		threading[1] = "dbm_th"
		threads = []
		timing = 0
		i = 1
		while ( i < 2 ) 
			threads << Thread.new(threading[i]) { |my_th|
#		this is the ftp
			if my_th == "dummy" then		#because FTP is really slow
#			if my_th == "ftp_th" then
				if @@ftp.get_time == "-" then 
					timing = Time.now.to_i	
				end	
				while (1) 
					if Time.now.to_i >= timing+3600 then 
						@@ftp.init_ftp
						if @@ftp.get_time == "-" then 
							timing = Time.now.to_i	
						end	
					end
					if Time.now.to_i >= @@ftp.get_time.to_i + @@ftp.get_last_time.to_i then
						@@ftp.ftp_startup(0)
						@@ftp.set_last_time(Time.now.to_i)
					end
				end
#		this is the databasemanager 
			else
				while (session = server.accept)
					message = String.new("")
					m = session.recv(256) 
					message << m 
					breaker = m.scan(/\S+/)
					if breaker[0] == "quit" then
						break 
					end
					parse_request(message,session)
					#session.close
				end
			end
			}
		i = i + 1
		end
		threads.each { |aThread|  aThread.join }
		
	end
#documents the change that has occur in the library
#saves the in the form of <hash> <rating> <playcount> <last_played>
	def Database_Manager.doc_change(pluginID,s)
		i = 0 
		infile = 0
		debug("Should ignore #{pluginID}")
		output = String.new("#{s.hash}\n")
		while (i < @current_players.length)
			if @current_players[i].to_s.chomp != pluginID.to_s.chomp  then
				plug = @current_players[i].to_s.chomp("\n")
				infile = File.new("#{plug}", File::RDWR|File::APPEND,0777)
				infile.write(output)
				infile.close
			else
			debug("Ignoring #{pluginID}")
			end
			i = i+1
		end
	end
#gives a plugin a new id that has not been used by another plugin
	def Database_Manager.get_id()
		number = 0
    debug "In get_id()"
		while(1) 
			i = 0
			conflict = 0
			number = rand()*1000 % 2152534153
      debug "Number: #{number}"
			while( i < @current_players.length)
				if number.to_i == @current_players[i] then 
					conflict = 1
					break
				end
				i=i+1
			end
			if conflict == 0 then 
				break
			end
		end
		return number.to_i
	end
end
